
<template>
    <div class="SimpleFrameSyncWrap" v-if="inGaming">
        <div
            class="Player"
            v-for="(player, connId) in allPlayers"
            :key="connId"
            v-bind:style="'left:' + player.x + 'px;top:' + player.z + 'px'"
        ></div>
        <!--准备使用players绑定列表,x和y都绑定上去,之后再加缓动-->
        <joystick
            @onmove="onJoysickMoveStart"
            @onmoveend="onJoysickMoveEnd"
        ></joystick>
    </div>
</template>
<style lang="less">
#SimpleFrameSyncWrap {
    width: 100vw;
    height: 100vh;
    position: absolute;
    overflow: hidden;
    top: 0;
    left: 0;
}
.Player {
    width: 10vw;
    height: 10vw;
    position: absolute;
    overflow: hidden;
    border: 1px solid #000;
}
</style>
<script lang="ts">
import { defineComponent } from "vue";
import { GameClient } from "../../assets/shared/gameClient/gameClient";
import { ConnectionInputOperate } from "../../assets/shared/gameClient/GameSyncFrame";
import Joystick from "../Joystick.vue";
import { InputType } from "../../assets/shared/gameClient/protocols/SimpleFrameSyncGame";
import { PlayerData } from "../../assets/PlayerData";
import { FrameSyncExecutor } from "../../assets/FrameSyncExecutor";


function playerUpdate(player: PlayerData, dt: number) {
    if (player.moveDirX != 0 || player.moveDirZ != 0) {
        //有移动,转向直接生效,小方块,懒得转忽略
        var distance = player.speed * dt;//本帧移动的距离

        var oldX = player.x;
        var oldZ = player.z;

        var cosA = Math.cos(player.moveAcuteRad);
        var sinA = Math.sin(player.moveAcuteRad);

        var stepReC = distance;

        var stepReX = player.moveDirZ == 0 ?
            player.moveDirX * distance : cosA * stepReC * player.moveDirX;//如果Z方向没动,直接用X方向的距离
        var stepReZ = player.moveDirX == 0 ?
            player.moveDirZ * distance : sinA * stepReC * player.moveDirZ;//如果X方向没动,直接用Z方向的距离

        player.x = oldX + stepReX;
        player.z = oldZ + stepReZ;
    }
}

var comp = defineComponent({
    name: "SimpleFrameSync",
    components: {
        Joystick,
    },
    props: {
        inGaming: Boolean,
    },
    data() {
        var frameSyncExecutor: FrameSyncExecutor | undefined;
        var allPlayers: { [key: string]: PlayerData } = {};

        return {
            allPlayers,
            frameSyncExecutor,
        };
    },
    methods: {
        execInput_NewPlayer(connId: string, inputFrame: ConnectionInputOperate, dt: number): void {
            const p = new PlayerData();
            p.connId = connId;
            p.userName = inputFrame.userName;
            this.allPlayers[connId] = p;
        },
        execInput_RemovePlayer(connId: string, inputFrame: ConnectionInputOperate, dt: number): void {
            const p = this.allPlayers[connId];
            delete this.allPlayers[connId];
        },
        execInput_MoveDirStart(connId: string, inputFrame: ConnectionInputOperate, dt: number): void {
            const player = this.allPlayers[connId] as PlayerData;
            if (!player) return;
            player.moveDirX = inputFrame.dirX;
            player.moveDirZ = inputFrame.dirZ;
            player.moveAcuteRad = inputFrame.acuteRad;
        },
        execInput_MoveDirEnd(connId: string, inputFrame: ConnectionInputOperate, dt: number): void {
            const player = this.allPlayers[connId];
            if (!player) return;
            player.moveDirX = 0;
            player.moveDirZ = 0;
            player.moveAcuteRad = 0;
        },
        onAfterFrames(stateData: any) {
            this.allPlayers = stateData;
        },
        executeOneFrame(dt: number): void {
            for (var connId in this.allPlayers) {
                var p = this.allPlayers[connId];
                playerUpdate(p, dt);
            }
        },
        startGame(gameClient: GameClient) {
            this.frameSyncExecutor = new FrameSyncExecutor(gameClient, this,
                (stateData) => this.onAfterFrames(stateData),
                (dt) => this.executeOneFrame(dt),
                () => this.allPlayers);
        },
        async stopGame(){
            this.frameSyncExecutor?.dispose();
        },
        onJoysickMoveStart(move: any) {
            this.frameSyncExecutor?.sendInputFrame(
                {
                    inputType: InputType.MoveDirStart,
                    dirX: move.dirX,
                    dirZ: move.dirZ,
                    acuteRad: move.acuteRad,
                }
            );
        },
        onJoysickMoveEnd() {
            this.frameSyncExecutor?.sendInputFrame(
                {
                    inputType: InputType.MoveDirEnd,
                }
            );
        },
    },
});

export default comp;
</script>